package com.hexacta.hrs.domain.staffing;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;

import com.hexacta.hrs.domain.staffing.assignment.AssignmentType;
import com.hexacta.hrs.domain.staffing.assignment.EmployeeAssignment;
import com.hexacta.hrs.domain.staffing.relationship.RequirementAssignmentRelationship;
import com.hexacta.hrs.domain.staffing.relationship.generators.AssignmentRelationshipGenerator;

/**
 * Representa un proyecto de la empresa.
 * Los proyectos pueden ser de clientes externos o propios de la empresa (internos).
 * 
 * @author ncortinez
 *
 */
public class Project implements Serializable {
	
	private static final long serialVersionUID = 1648863166018586161L;
	
	private Long id;
	private String name = null;
	private String description = null;
	private Calendar dateStart = null;
	private Calendar dateEnd = null;
	private Client client = null;
	private List<EmployeeAssignment> assignments = new ArrayList<EmployeeAssignment>();
	private List<Requirement> requirements = new ArrayList<Requirement>();
	
	// Un proyecto es interno si el cliente es la misma empresa.
	public boolean isInternalProject()
	{
		return ((client != null)&&(client.isInternal()));
	}

	// Devuelve todos los Assigned Requirements.
	// Assigned Requirement: es el caso en el que una asignacion esta cubriendo un requerimiento de un proyecto.
	public List<RequirementAssignmentRelationship> getAssignedRequirements(){
		AssignmentRelationshipGenerator generator = new AssignmentRelationshipGenerator();
		return generator.getAssignedRequirements(this.getRequirements(), this.getAssignmentsExceptAddOns());
	}
	
	// Devuelve todos los Non Requirement Assignment.
	// Non Requirement Assignment: es el caso en el que un recurso esta asignado a un proyecto, pero no existe un requerimiento que lo concuerde.
	public List<RequirementAssignmentRelationship> getNonRequirementAssignments(){
		AssignmentRelationshipGenerator generator = new AssignmentRelationshipGenerator();
		return generator.getNonRequirementAssignments(this.getRequirements(), this.getAssignmentsExceptAddOns());
	}

	// Devuelve todos los Unassigned Requirements.
	// Unassigned Requirement: es el caso en que un requerimiento no es cubierto por una asignacion.
	public List<RequirementAssignmentRelationship> getUnassignedRequirements(){
		AssignmentRelationshipGenerator generator = new AssignmentRelationshipGenerator();
		return generator.getUnassignedRequirements(this.getRequirements(), this.getAssignmentsExceptAddOns());
	}

	// Devuelve todas las asignaciones del tipo Assigned (no devuelve asignaciones del tipo Add On).
	public List<EmployeeAssignment> getAssignmentsExceptAddOns() {
		List<EmployeeAssignment> assignmentsExceptAddOns = 
			(List<EmployeeAssignment>) CollectionUtils.select(this.assignments, new Predicate(){
				@Override
				public boolean evaluate(Object arg) {
					return ((EmployeeAssignment)arg).getAssignmentType().equals(AssignmentType.Assigned);
				}
			});
		return assignmentsExceptAddOns;
	}
	
	// Devuelve todas las asignaciones del tipo Add On.
	public List<EmployeeAssignment> getAddOnAssignments() {
		List<EmployeeAssignment> addOnAssignments = 
			(List<EmployeeAssignment>) CollectionUtils.select(this.assignments, new Predicate(){
				@Override
				public boolean evaluate(Object arg) {
					return ((EmployeeAssignment)arg).getAssignmentType().equals(AssignmentType.AddOn);
				}
			});
		return addOnAssignments;
	}
	
	// Agrega un requerimiento al proyecto.
	public void addRequirement(Requirement requirement)
	{
		this.getRequirements().add(requirement);
	}
	
	// Agrega una asignacion de un empleado al proyecto.
	public void addAssignment(EmployeeAssignment employeeAssignment)
	{
		employeeAssignment.setProject(this);
		this.getAssignments().add(employeeAssignment);
	}
	
	// Elimina una asignacion de las asignacion del proyecto.
	public void removeAssignment(EmployeeAssignment employeeAssignment)
	{
		this.getAssignments().remove(employeeAssignment);
	}
	
	// Elimina un requerimiento de los requerimientos del proyecto.
	public void removeRequirement(Requirement requirement) {
		this.getRequirements().remove(requirement);
	}

	/**
	 * GETTERS and SETTERS 
	 */
	
	public List<EmployeeAssignment> getAssignments() {
		return this.assignments;
	}
	public void setAssignments(List<EmployeeAssignment> assignments) {
		this.assignments = assignments;
	}
	public void setRequirements(List<Requirement> requirements) {
		this.requirements = requirements;
	}
	public List<Requirement> getRequirements() {
		return this.requirements;
	}
	public void setClient(Client client) {
		this.client = client;
	}
	public Client getClient() {
		return client;
	}
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public Calendar getDateStart() {
		return dateStart;
	}
	public void setDateStart(Calendar dateStart) {
		this.dateStart = dateStart;
	}
	public Calendar getDateEnd() {
		return dateEnd;
	}
	public void setDateEnd(Calendar dateEnd) {
		this.dateEnd = dateEnd;
	}

}
